package fr.jade.util;

import java.util.Set;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.Interface;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.ContentController;
import org.objectweb.fractal.api.control.NameController;
import org.objectweb.fractal.api.control.SuperController;
import org.objectweb.fractal.api.type.InterfaceType;

import fr.jade.reflex.util.Reflex;
import fr.jade.util.log.Logger;
import fr.jade.util.log.config.DebugService;
import fr.jade.util.log.config.LogReflex;

/**
 * @author ssicard
 *
 */
public class FractalPrinter {

	
	public static void printCmp(Component cmp){
		try{
			Logger.println(FractalNavigator.getName(cmp));
			print(cmp,"");
		}catch(Exception e){
			Logger.println("ERROR");
			Logger.println(e);
		}
	}
	
	public static void print(Component c, String separ) throws Exception {
		String n;
		Component[] cimplsub16;
		
		try {
			cimplsub16 = ((ContentController) (c.getFcInterface("content-controller"))).getFcSubComponents();
		} catch (Exception e) {
			
			cimplsub16 = null;
		}
		if (cimplsub16 != null) {
			
			try {
				
				for (int i = 0; i < cimplsub16.length; i++) {
						n = ((NameController) (c.getFcInterface("name-controller"))).getFcName();

						Logger.println(separ + "|___" + ((NameController) (cimplsub16[i].getFcInterface("name-controller"))).getFcName());
						print(cimplsub16[i], "|   " + separ);
				}
			} catch (Exception e) {
				Logger.println(LogReflex.info, "Jade:visit:error:" + e);
			}
		}
	}
	
	public static void printCmpAttributes(Component cmp){
		try{
			Logger.println("Attributes of "+FractalNavigator.getName(cmp)+" :");
			
			for ( String attName : FractalUtil.getAttributeController(cmp).listFcAtt() ) {
				Logger.println("\t-"+attName+"="+FractalUtil.getAttributeController(cmp).getAttribute(attName));
			}
			
		}catch(Exception e){
			Logger.println("Error while introspecting interfaces of cmp.");
			Logger.println(e);
		}
	}
	
	public static void printCmpInterfaces(Component cmp){
		try{
			Logger.println("Interface of "+FractalNavigator.getName(cmp)+" :");
			
			Object[] itfs = cmp.getFcInterfaces();
			
			for(int i=0; i<itfs.length; i++){
				Logger.println("\t - "+((Interface)itfs[i]).getFcItfName());
			}

		}catch(Exception e){
			Logger.println("Error while introspecting interfaces of cmp.");
			Logger.println(e);
		}
	}
	
	public static void printInterface(Interface itf){
		try{
		
			Logger.println("itf name : "+itf.getFcItfName());
			Logger.println("\tinternal itf  : "+itf.isFcInternalItf());
			Logger.println("\titf owner : "+FractalNavigator.getName(itf.getFcItfOwner()));
		}catch(Exception e){
			Logger.println("Error while introspecting interface.");
			Logger.println(e);
		}
	}
	
	
	public static void printExecSuperCmp(Component cmp_M) {
		Component cmp_E;
		try {
			cmp_E = Reflex.getOptDualComponent(cmp_M);
			Logger.println(DebugService.info, "INSPECTING supercmp of " + FractalNavigator.getName(cmp_E));

			Component[] peres = FractalUtil.getOptSuperController(cmp_E).getFcSuperComponents();
			if (peres != null) {
				for (int i = 0; i < peres.length; i++) {
					Logger.println(DebugService.info, "-> -> " + FractalNavigator.getName(peres[i]));
				}
			}
		} catch (Exception e) {/*= =*/}
	}

	public static void printExtClientBinding(Component cmp) {
		Component servCmp;
		Interface servItf;
		BindingController execBC;
		String execName;
		String itfName;
		String servItfName;
		String servCmpName;

		boolean isClient;

		try {
			execBC = FractalUtil.getBindingController(cmp);
			execName = FractalNavigator.getName(cmp);

			Logger.println(DebugService.info,"INSPECTING external client binding of " + execName);
			Object[] execItf = cmp.getFcInterfaces();
			if (execItf != null) {
				for (int i = 0; i < execItf.length; i++) {
					itfName = ((Interface) (execItf[i])).getFcItfName();
					isClient = ((InterfaceType) (((Interface) (execItf[i])).getFcItfType())).isFcClientItf();
					if (isClient) {
						servItf = (Interface) execBC.lookupFc(itfName);
						if (servItf != null) {
							servItfName = servItf.getFcItfName();
							servCmp = servItf.getFcItfOwner();
							servCmpName = FractalNavigator.getName(servCmp);
							Logger.println(DebugService.info, " -> -> " + execName + "/" + itfName + " bound to "+ servCmpName + "/" + servItfName);
						} else {
							Logger.println(DebugService.info, " -> -> " + execName + "/" + itfName + " not bound ");
						}
					} else {/* server itf */}
				}
			}
		} catch (Exception e) {/*= =*/}
	}

	public static void printExecIntClientBinding(Component cmp_M) {
		Component cmp_E;
		Component servCmp;
		Interface servItf;
		BindingController execBC;
		String execName;
		String itfName;
		String servItfName;
		String servCmpName;
		ContentController execCC;

		boolean isClient;

		try {
			cmp_E = Reflex.getOptDualComponent(cmp_M);
			execBC = FractalUtil.getBindingController(cmp_E);
			execName = FractalNavigator.getName(cmp_E);

			try {
				execCC = FractalUtil.getOptContentController(cmp_E);
			} catch (NoSuchInterfaceException e) {
				execCC = null;
			}
			if (execCC != null) {
				Logger.println(DebugService.info,"INSPECTING internal client binding of " + execName);
				Object[] execItf = execCC.getFcInternalInterfaces();
				if (execItf != null) {
					for (int i = 0; i < execItf.length; i++) {
						itfName = ((Interface) (execItf[i])).getFcItfName();
						isClient = ((InterfaceType) (((Interface) (execItf[i])).getFcItfType())).isFcClientItf();
						if (isClient) {

							servItf = (Interface) execBC.lookupFc(itfName);
							if (servItf != null) {
								servItfName = servItf.getFcItfName();
								servCmp = servItf.getFcItfOwner();
								servCmpName = FractalNavigator.getName(servCmp);
								Logger.println(DebugService.info, " -> -> "+ execName + "/" + itfName+ " bound to " + servCmpName + "/"+ servItfName);
							} else {
								Logger.println(DebugService.info, " -> -> "+ execName + "/" + itfName+ " not bound ");
							}
						} else {
							// server itf
						}
					}
				}
			}
		} catch (Exception e) {

		}
	}

	public static void printMetaSuperCmp(Component meta) {
		Component exec;
		try {
			Logger.println(DebugService.info, "INSPECTING supercmp of " + FractalNavigator.getName(meta));

			Component[] peres = FractalUtil.getOptSuperController(meta).getFcSuperComponents();
			if (peres != null) {
				for (int i = 0; i < peres.length; i++) {
					Logger.println(DebugService.info, "-> -> " + FractalNavigator.getName(peres[i]));
				}
			}
		} catch (Exception e) {}
	}
	
	public static void toString (
      final Component component,
      final StringBuffer buf)
    {
      try {
        NameController nc =
          (NameController)component.getFcInterface("name-controller");
        try {
          SuperController sc =
            (SuperController)component.getFcInterface("super-controller");
          Component[] superComponents = sc.getFcSuperComponents();
          if (superComponents.length > 0) {
            toString(superComponents[0], buf);
          }
        } catch (NoSuchInterfaceException ignored) {
        }
        buf.append('/');
        buf.append(nc.getFcName());
      } catch (NoSuchInterfaceException e) {
        buf.append(component.toString());
        return;
      }
    }
	
	public static void printComponentSet(String msg, Set<Component> sibling) {
    Logger.println(msg);
    for(Component cmp : sibling){
      Logger.println(FractalNavigator.getName(cmp)+" - hashCode:"+cmp.hashCode()+" - ItfId:"+((Interface)cmp).getFcItfGUId());
    }
  }
//	public static void printRawNames(List<Component> list){
//    for(Component cmp : list){
//      try{
//        System.out.print(FractalNavigator.getNameController(cmp).getFcName());
//      }catch(NoSuchInterfaceException e){}
//      try{
//        Identifier id = ((Stub)cmp).getIdentifiers()[0];
//        System.out.print("{" + id + "}");
//      }catch(ClassCastException ignored){}
//      System.out.print("{"+cmp+"}");
//      System.out.print(" / ");
//    }
//    System.out.println("");
//  }
}
